<?php
require_once(MODEL_DIR .  '/Model.php');
require_once('Content.php');
require_once('NoSuchContentException.php');
require_once('ContentCreationException.php');
require_once(MODEL_DIR . '/User/UserFactory.php');

/**
 * 
 * The ContentFactory class allows us to access the data source in order to obtain 
 * information about content in the data source. We can also extract Content objects
 * from the data source, which are simply thing wrappers around the raw data itself, 
 * with some convienence methods to make creating and updating Content objects simpler.
 * 
 * @author Rick Hutcheson
 *
 */
class ContentFactory extends Model {
	
	const TEXT_CLASS = 1;
	const FILE_CLASS = 2;
    
    public function __construct() {
		// we now have access to $this->database
		parent::__construct();
	}
	
    
    
	/**
	 * 
	 * This function, given an ID and (optiornally) the content information associated 
	 * with the id, will query the other data source inputs needed for all Content 
	 * creation, such as querying for Content tags, comments, authors, etc. It then 
	 * returns a Content object, which can be used for display or modification within 
	 * the system.
	 * 
	 * @param int $id
	 * 	The id of the Content object to be created inside of the data source.
	 * @param array $contentInfo
	 * 	An array of the Content's information. If this information is not provided, 
	 * 	the function will query the Content data source to provide this information.
	 * 
	 * @retval Content
	 * 	A Content object with its fields initialized to the values stored within the data 
	 * 	source.
	 */
	private function createContentFromID($id, $contentInfo = array()) {
        if (empty($contentInfo)) {
            $contentStmt = $this->database->query(
                    "SELECT * FROM content WHERE id = {$id}");
            $contentStmt->setFetchMode(PDO::FETCH_ASSOC);
            $contentInfo = $statement->fetch();   
        }   
		
        // Get author from database.
        $factory = new UserFactory();
        $aname = $contentInfo['author'];
        $author = $factory->getUserFromUsername($aname);

        // Get comments from database.
        $commentStmt = $this->database->query(
                                        "SELECT * FROM comments WHERE content_id = {$id}");
        $commentStmt->setFetchMode(PDO::FETCH_ASSOC);
        $comments = array();

        while ($commentInfo = $commentStmt->fetch()) {
            $comments[] = $commentInfo;
        }


        // Get tags from database.
        $tagIDStmt = $this->database->query(
                "SELECT tag_id FROM content_tags WHERE content_id = {$id}");
        $tagIDStmt->setFetchMode(PDO::FETCH_ASSOC);

        $tags = array();
        while ($tagIDInfo = $tagIDStmt->fetch()) {
        $id = $tagIDInfo['tag_id'];
        $tagStmt = $this->database->query(
                    "SELECT tag FROM tags WHERE id = {$id}");
        $tagStmt->setFetchMode(PDO::FETCH_ASSOC);
        $tagInfo = $tagStmt->fetch();

        $tags[] =  $tagInfo['tag'];
        }

        // Get attachments from database.
        // TODO: Add the proper prefix to these filenames. 
        // This is part of the config file.
        $attachStmt = $this->database->query(
            "SELECT * FROM attachments WHERE content_id = {$id}");
        $attachStmt->setFetchMode(PDO::FETCH_ASSOC);
        $attachments = array();
        while ($attachmentInfo = $attachStmt->fetch()) {
                $attachments[] = $attachmentInfo;
        }

        // Create content object.
        $article = new Content( $contentInfo['id'], $contentInfo['type_id'], 
                                $contentInfo['title'], $author, $contentInfo['date'], 
                                $contentInfo['content']);

        $article->setComments($comments);
        $article->setTags($tags);
        $article->setAttachments($attachments);		
        $article->setDescription($contentInfo['description']);

        return $article;
	}
	
	/**
	 * 
	 * Returns the most recently created content; that is, the content with the
	 * highest ids, since the id of an article is autogenerated in order. If no
	 * content exists in the database, then the function will throw a 
	 * NoSuchContentException. If fewer content objects exist than the number listed in 
	 * the parameter, the function will return all of them. Also note that this function
	 * is type-agnostic.
	 * 
	 * @param int $limit	
	 * 	The number of content objects to return.
	 * 
	 * @throws NoSuchContentException
	 */
	public function getLatestContent($limit = 1) {
		$stmt = $this->database->query(
								"SELECT * FROM content ORDER BY id DESC LIMIT {$limit}");
		$stmt->setFetchMode(PDO::FETCH_ASSOC);
		
		$contentArray = array();
		while ($info = $stmt->fetch()) {
			$content= $this->createContentFromID($info['id'], $info);
			$contentArray[] = $content;
		}
		
		//No articles exist in database, throw exception now.
		if (empty($contentArray)) {
			throw new NoSuchContentException($message, $code, $previous);
		} else {
			return $contentArray;
		}
	}
	
	/**
	 * 
	 * Returns a Content object initialized to the data from the article with the 
	 * specified id. If no such Contetn exists, then the function will throw a 
	 * NoSuchContentException.
	 * 
	 * @param int $id
	 * 	The id of the content object to return.
	 * 
	 * @throws NoSuchContentException
	 */
	public function getContentByID($id) {
		
		$stmt = $this->database->prepare("SELECT * FROM content WHERE id = ?");
		$stmt->bindParam(1, $id);
		$stmt->execute();
		$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
		if(!empty($result)) {
			return $this->createContentFromID($id. $result[0]);
		} else {
			throw new NoSuchContentException();
		}
	}
	
	/**
	 * 
	 * Given a Content object, this function will attempt to add it to the data source.
	 * If the attempt fails, then the function will fail with a ContentCreationException.
	 * 
	 * @param Content $c
	 * 	The Content object whose values will be inserted into the data source.
	 * 
	 * @throws ContentCreationException 
	 */
	public function createContent(Content $c) {
		// id,type_id, title, author, date, content, description
		$stmt = $this->database->prepare(
						"INSERT INTO content VALUES (NULL, :type_id, :title, :author, 
													:date, :content, :desc)");
		
		// Line of defense #2. This error checking should only occur if the user has
		// javascript turned off.

        $type = $c->getType();  
        $title = $c->getTitle();
        $author = $c->getAuthor()->getUsername();
        $date = $c->getDate()->format('Y-m-d');
        $desc = $c->getDescription();
        $content = $c->getContent();
    	
        $stmt->bindParam(':type_id', $type);
		$stmt->bindParam(':title', $title);
		$stmt->bindParam(':author', $author);
		$stmt->bindParam(':date', $date);
		$stmt->bindParam(':content', $content);
		$stmt->bindParam(':desc', $desc);
        
		
        if(!$stmt->execute()) {
            print_r($stmt->errorInfo());
			throw new ContentCreationException("database");
            
		} else {
            $thisContent = $this->getLatestContent(1); 
                $id = $thisContent[0]->getID();
            
            foreach ($tags as $tag) {
                $tag_stmt = $this->database->prepare("INSERT INTO content_tags VALUES($id, )");
            }
            
        }
        
	}
    
    public function createContentFromInput($type, $title, $author, $date, $content, $description, $tags) {
    if (strlen($title) == 0) {
        throw new ContentCreationException("title");
    } elseif (strlen($content) == 0) {
        throw new ContentCreationException("content");
    } elseif (strlen($date) == 0) {
        throw new ContentCreationException("date");
	} elseif (strlen($description) == 0) {
        throw new ContentCreationException("description");
    }
    
        $tagArray = explode(",", $tags);
		$c = new Content($type, null, $title, $author, $date, $content);
        $c->setDescription($description);
        $c->setTags($tagArray);
        $this->createContent($c);
	}
	
	
	/**
	*
	* Given a Content object, this function will attempt to update its values in the 
	* data source. If the attempt fails, then the function will fail with a 
	* ContentCreationException.
	*
	* @param Content $c
	* 	The Content object whose values will be update in the data source.
	*
	* @throws ContentCreationException
	*/	
	public function updateArticle(Article $a) {
		// id,type_id, title, author, date, content, description
		$stmt = $this->database->prepare("UPDATE content SET type_id = :type_id, 
															title = :title, 
															author = :author, 
															date = :date, 
															content = :content, 
															description = :desc 
															WHERE id = {$c->getID()}");
		
		// Line of defense #2. This error checking should only occur if the user has
		// javascript turned off.
	
		
		$stmt->bindParam(':type_id', $c->getType());
		$stmt->bindParam(':title', $c->getTitle());
		$stmt->bindParam(':author', $c->getAuthor()->getUsername());
		$stmt->bindParam(':date', $c->getDate()->format('Y-m-d'));
		$stmt->bindParam(':content', $c->getContent());
		$stmt->bindParam(':desc', $c->getDescription());
		
		if(!$stmt->execute()) {
			throw new ContentCreationException("database");
		}	
	}
	
	/**
	*
	* Given a Content object's ID, this function will remove it from the data source.
	*
	* @param int $id
	* 	The id of the Content object to be removed from the data source.
	*
	*/
	public function deleteArticle($id) {
		$this->database->exec("DELETE FROM content WHERE id = {$id}");
	}
	
	//TODO: Searching functions here.
	/*
	public function numberOfArticles((optional) $title,  (optional)  $author, (optional) $date, (optional) $text, (optional) array $tags, (optional) $limit, (optional) $order) {
		
	}
	public function searchArticlesByTitle($title, (optional) $limit, (optional) $order) {
		
	}
	public function searchArticlesByDate($date,  (optional) $limit, (optional) $order) {
		
	}
	public function searchArticlesByText($search, (optional) $limit, (optional) $order) {
		
	}
	public function searchArticlesByTag($search, (optional) $limit, (optional) $order) {
		
	}
	public function searchArticlesByAuthor($title, (optional) $limit, (optional) $order) {
		
	}
	
	*/
	
	/**
	 * 
	 * Returns an array of the content types currently stored in the data source.
	 * @retval array
	 * 	The content types and their descriptions currently stored in the data source.
	 */
	public function getContentTypes() {
		$stmt = $this->database->prepare("SELECT * FROM content_types");
		$stmt->execute();
		$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
		return $result;
    }
	
    public function getContentTypeIdByName($name) {
        $stmt = $this->database->prepare("SELECT * FROM content_types WHERE 
                                type = '$name'");
		$stmt->execute();
		$result = $stmt->fetch(PDO::FETCH_ASSOC);
		return $result['id'];
    }
    
    public function getContentTypeClassByName($name) {
        $stmt = $this->database->prepare("SELECT * FROM content_types WHERE 
                                type = '$name'");
		$stmt->execute();
		$result = $stmt->fetch(PDO::FETCH_ASSOC);
		return $result['class'];
    }
    
	public function __destruct() {
		parent::__destruct();
	}
	
	

}